﻿using System;
using Deferred.Library.Scene.Utilities;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Deferred.Library.Scene.Visual
{
    class TerrainVisual : GraphicalComponent
    {
        private DualContentManager content;
        private TerrainBuilder builder;
        private Texture2D lowTexture;
        private Texture2D lowNormal;
        private Texture2D midTexture;
        private Texture2D midNormal;
        private Texture2D highTexture;
        private Texture2D highNormal;
        private Texture2D slopeTexture;
        private Texture2D slopeNormal;

        protected override bool LoadContentUponCreation { get { return false; } }

        public Terrain Terrain { get; private set; }

        public Texture2D LowTexture { get { return lowTexture; } set { lowTexture = value; } }
        public Texture2D LowNormal { get { return lowNormal; } set { lowNormal = value; } }
        public Texture2D MidTexture { get { return midTexture; } set { midTexture = value; } }
        public Texture2D MidNormal { get { return midNormal; } set { midNormal = value; } }
        public Texture2D HighTexture { get { return highTexture; } set { highTexture = value; } }
        public Texture2D HighNormal { get { return highNormal; } set { highNormal = value; } }
        public Texture2D SlopeTexture { get { return slopeTexture; } set { slopeTexture = value; } }
        public Texture2D SlopeNormal { get { return slopeNormal; } set { slopeNormal = value; } }

        public VertexDeclaration VertexDeclaration { get { return builder.GraphicsData.vertexDeclaration; } }
        public IndexBuffer IndexBuffer { get { return builder.GraphicsData.iBuffer; } }
        public VertexBuffer VertexBuffer { get { return builder.GraphicsData.vBuffer; } }
        public int VertexCount { get { return builder.GraphicsData.vertexCount; } }
        public int TriangleCount { get { return builder.GraphicsData.triangleCount; } }

        public TerrainVisual(DeferredBase deferredBase, Terrain terrain)
            : base(deferredBase.DeviceService)
        {
            this.content = deferredBase.Content;
            this.Terrain = terrain;
            EventHandler terrainChangedHandler = new EventHandler(delegate(object o, EventArgs a) { LoadContent(); });
            this.Terrain.OnHeightmapNameChanged += terrainChangedHandler;
            this.Terrain.GenerationData.OnChanged += terrainChangedHandler;
            this.Terrain.TexturePack.OnTextureNameChanged += terrainChangedHandler;

            if (GraphicsDevice != null) LoadContent();
        }

        protected override void LoadContent()
        {
            builder = new TerrainBuilder(GraphicsDevice, Terrain.GenerationData);
            Texture2D texture = builder.Heightmap;
            LoadTexture(out texture, Terrain.HeightmapName);
            builder.Heightmap = texture;
            LoadTexture(out lowTexture, Terrain.TexturePack.LowTextureName);
            LoadTexture(out lowNormal, Terrain.TexturePack.LowNormalName);
            LoadTexture(out midTexture, Terrain.TexturePack.MidTextureName);
            LoadTexture(out midNormal, Terrain.TexturePack.MidNormalName);
            LoadTexture(out highTexture, Terrain.TexturePack.HighTextureName);
            LoadTexture(out highNormal, Terrain.TexturePack.HighNormalName);
            LoadTexture(out slopeTexture, Terrain.TexturePack.SlopeTextureName);
            LoadTexture(out slopeNormal, Terrain.TexturePack.SlopeNormalName);

            builder.Build();
        }

        private void LoadTexture(out Texture2D texture, string textureName)
        {
            if (!string.IsNullOrEmpty(textureName))
            {
                try
                {
                    texture = content.ExternalContent.Load<Texture2D>(textureName);
                }
                catch (ContentLoadException)
                {
                    LoadDefaultTexture(out texture);
                }
            }
            else
            {
                LoadDefaultTexture(out texture);
            }
        }

        private void LoadDefaultTexture(out Texture2D texture)
        {
            texture = content.InternalContent.Load<Texture2D>("_default");
        }
    }
}
